
# include  "pform.h"
# include  "PClass.h"
# include  "PEvent.h"
# include  "PGenerate.h"
# include  "PPackage.h"
# include  "PScope.h"
# include  "PSpec.h"
# include  "parse_api.h"
# include  "Mynetlist.h"
#include "utils.h"
#include <algorithm>
#include <typeinfo>

void elaborate_binary(PEBinary* root, vector<MYCELL>& cells, string name);
void elaborate_unary(PEBinary* root, vector<MYCELL>& cells, string name);

int x = 0;

void elaborate_exp(PEBinary* root, vector<MYCELL>& cells, string name) {
	char c = root->get_op();
	if (c == '|')
		cells[0].type = "$or";
	else if (c == '&')
		cells[0].type = "$and";
	else if (c == '+')
		cells[0].type = "$add";
	else if (c == '-')
		cells[0].type = "$sub";
	else if (c == '*')
		cells[0].type = "$mul";
	else if (c == '/')
		cells[0].type = "$div";
	else if (c == '>')
		cells[0].type = "$gre";
	else if (c == '<')
		cells[0].type = "$les";
	else if (c == 'G')//大于等于
		cells[0].type = "$ge";
	else if (c == 'L')//小于等于
		cells[0].type = "$le";
	else if (c == '~')
		cells[0].type = "$not";
	else if (c == 'p')//条件运算符
		cells[0].type = "$tiao";
	else if (c == '^')//异或
		cells[0].type = "$xor";
	else if (c == 'X')//同或
		cells[0].type = "$xnor";

		//if (c == '|' || c == '&' || c == '+' || (c == '-' && sub == 0) || c == '*' || c == '/' || c == 'G' || c == 'L' || c == '>' || c == '<')
	if (typeid(*root) == typeid(PEBinary))
		elaborate_binary(root, cells, name);
	else if (typeid(*root) == typeid(PEUnary))
		elaborate_unary(root, cells, name);
	else if (typeid(*root) == typeid(PETernary))
		;
}

void elaborate_binary(PEBinary* root, vector<MYCELL>& cells, string name) {
	//本级的输出
	MYPORT* co = new MYPORT();
	co->portname = 'y';
	co->inout_type = '1';
	cells[0].cell_conns.insert({ name,*co });

	int l = 0, r = 0;//标记左右是否为运算
	string lname = "tmp", rname = "tmp";//左右两边的临时端口名

	PExpr* Pleft = root->get_left();
	if (typeid(*Pleft) == typeid(PEIdent)) {
		PEIdent* left = (PEIdent*)Pleft;
		perm_string lname = (*left->path().begin()).name;
		std::string l = (char*)lname.str();
		MYPORT* lp = new MYPORT();
		lp->portname = 'a';
		lp->inout_type = '0';
		cells[0].cell_conns.insert({ l,*lp });
	}
	else {//左边是运算
		x++;
		lname += to_string(x);
		MYPORT* p = new MYPORT();
		p->portname = 'a';
		p->inout_type = '0';
		cells[0].cell_conns.insert({ lname + "in",*p });
		l = 1;
	}

	PExpr* Pright = root->get_right();
	if (typeid(*Pright) == typeid(PEIdent)) {
		PEIdent* right = (PEIdent*)Pright;
		perm_string rname = (*right->path().begin()).name;
		std::string r = (char*)rname.str();
		MYPORT* rp = new MYPORT();
		rp->portname = 'b';
		rp->inout_type = '0';
		cells[0].cell_conns.insert({ r,*rp });
	}
	else {//右边边是运算
		x++;
		rname += to_string(x);
		MYPORT* p = new MYPORT();
		p->portname = 'b';
		p->inout_type = '0';
		cells[0].cell_conns.insert({ rname + "in",*p });
		r = 1;
	}
	if(l == 1){
		cells.insert(cells.begin(), *new MYCELL());
		elaborate_exp((PEBinary*)Pleft, cells, lname + "out");
	}
	if(r == 1){
		cells.insert(cells.begin(), *new MYCELL());
		elaborate_exp((PEBinary*)Pright, cells, rname + "out");
	}
	return;
}

void elaborate_unary(PEBinary* root, vector<MYCELL>& cells, string name) {
	MYPORT* co = new MYPORT();
	co->portname = 'y';
	co->inout_type = '1';
	cells[0].cell_conns.insert({ name,*co });

	int l = 0;//标记左是否为运算
	string lname = "tmp";//左边的临时端口名

	PExpr* Pleft = root->get_left();
	if (typeid(*Pleft) == typeid(PEIdent)) {
		PEIdent* left = (PEIdent*)Pleft;
		perm_string lname = (*left->path().begin()).name;
		std::string l = (char*)lname.str();
		MYPORT* lp = new MYPORT();
		lp->portname = 'a';
		lp->inout_type = '0';
		cells[0].cell_conns.insert({ l,*lp });
	}
	else {//左边是运算
		x++;
		lname += to_string(x);
		MYPORT* p = new MYPORT();
		p->portname = 'a';
		p->inout_type = '0';
		cells[0].cell_conns.insert({ lname + "in",*p });
		l = 1;
	}

	if (l == 1) {
		cells.insert(cells.begin(), *new MYCELL());
		elaborate_exp((PEBinary*)Pleft, cells, lname + "out");
	}
	return;
}

int get_fileline()
{
	return 0;
}
MyScope::MyScope(void)
{

}

MyScope::~MyScope(void)
{

}

void MyScope::set_num_ports(unsigned int num_ports)
{
	ports.resize(num_ports);
}

MyModule::MyModule(void)
{

}

MyModule::~MyModule(void)
{

}
MyDesign::MyDesign(void)
{

}

MyDesign::~MyDesign(void)
{

}
std::vector<std::string> GetInName(MYCELL& cell) {
	std::vector<std::string> pname;
	for (auto itr = cell.cell_conns.begin(); itr != cell.cell_conns.end(); itr++) {
		if ((*itr).second.inout_type == '0') {
			pname.push_back((*itr).first);
		}
	}
	return pname;
}

std::string GetOutName(MYCELL& cell) {
	for (auto itr = cell.cell_conns.begin(); itr != cell.cell_conns.end(); itr++) {
		if ((*itr).second.inout_type == '1') {
			return itr->first;
		}
	}
	return "not found";
}

void ChangePortName(string des, string src, std::vector<MYCELL>& cells) {
	for (auto itr = cells.begin(); itr != cells.end(); itr++) {
		for (auto mapit = (*itr).cell_conns.begin(); mapit != (*itr).cell_conns.end(); mapit++) {
			if ((*mapit).first.substr(0, (*mapit).first.size() - 2) == des.substr(0, des.size() - 3)) {//此处有误
				MYPORT tmp = (*mapit).second;
				mapit = (*itr).cell_conns.erase(mapit);
				if (src.size() >= 3 && strncmp(src.substr(0, 3).c_str(), "tmp", 3) == 0)
					(*itr).cell_conns.insert({ src.substr(0, src.size() - 3) + "in",tmp });
				else
					(*itr).cell_conns.insert({ src,tmp });
				return;
			}
		}
	}
}
bool IsSameIn(vector<string>& a, vector<std::string>& b) {
	if (a.size() != b.size()) return false;

	sort(a.begin(), a.end());
	sort(b.begin(), b.end());
	int s = a.size();
	for (int i = 0; i < s; i++) {
		if (a[i] != b[i]) return false;
	}
	return true;
}

void DetectUsed(string name, std::vector<MYCELL>& cells) {
	for (auto it = cells.rbegin(); it != cells.rend(); it++) {
		if ((*it).cell_conns.count(name) == 1 && (*it).isused == false && (*it).cell_conns[name].inout_type == '1') {
			(*it).isused = true;
			vector<string> inname = GetInName(*it);
			for (string a : inname) {
				if(strncmp(a.substr(0,3).c_str(), "tmp",3) == 0)
					a = a.substr(0, a.size() - 2) + "out";
				DetectUsed(a, cells);
			}
			break;
		}
	}
}
void DelNotUsed(std::vector<MYCELL>& cells) {
	auto it = cells.begin();
	while (it != cells.end()) {
		if ((*it).isused == false) {
			it = cells.erase(it);
			continue;
		}
		it++;
	}

}

bool MyModule::elaborate_sig(Module* rmod)
{
	bool flag = true;
	//get wire
	for (map<perm_string, PWire*>::const_iterator wt = rmod->wires.begin()
		; wt != rmod->wires.end(); ++wt) {

		PWire* cur = (*wt).second;
		MYWIRE tmp;
		tmp.name = cur->basename();
		tmp.porttype = (enum MY_PORT_TYPE)cur->get_port_type();
		wires.push_back(tmp);
	}
	///get port
	for (unsigned idx = 0; idx < rmod->ports.size(); idx += 1) {
		Module::port_t* pp = rmod->ports[idx];
		MYPORT tmp;
		const char* namestr = pp->name.str();

		char namestr2 = *namestr - 32;//小写转大写//可能导致乱码
		tmp.portname += namestr2;
		tmp.inout_type = '0';
		ports.push_back(tmp);
	}
	///get cell
	std::list<PGate*> gates = rmod->get_gates();
	int newcellnum = 1;
	for (auto it = gates.begin(); it != gates.end(); ++it) {
		PGate* gate = *it;
		vector<MYCELL> tmp(1);


		PEIdent* outpin = (PEIdent*)gate->pin(0); // 获取输出		
		perm_string outname = (*outpin->path().begin()).name;
		std::string out = (char*)outname.str();

		PEBinary* pin = (PEBinary*)gate->pin(1); // 获取操作和输入


		elaborate_exp(pin, tmp, out);

		int gap;
		for (auto tmpit = tmp.begin(); tmpit < tmp.end(); tmpit++) {
			gap = distance(tmp.begin(), tmpit);
			tmpit->name = '$';
			tmpit->name += std::to_string(newcellnum + gap);
			cells.push_back(*tmpit);
		}
		newcellnum += gap + 1;

	}

	//共享子表达式删除
	if (cells.size() == 0) return true;
	auto slow = cells.begin();
	while (slow != cells.end()) {
		auto fast = slow + 1;
		std::vector<std::string> spname = GetInName(*slow);
		std::string soname = GetOutName(*slow);
		while (fast != cells.end()) {
			if ((*fast).type == (*slow).type && (*fast).cell_conns.size() == (*slow).cell_conns.size()) {
				std::vector<std::string> fpname = GetInName(*fast);
				//if ((spname[0] == fpname[0] && spname[1] == fpname[1]) || (spname[0] == fpname[1] && spname[1] == fpname[0])) {
				if (IsSameIn(spname,fpname)) {
					//改变删除前后的端口名
					std::string foname = GetOutName(*fast);
					if (strcmp(foname.substr(0, 3).c_str(), "tmp") != 0)//若输出端口不是tmp而是某些wire
						(*slow).towires.push_back(foname);
					fast = cells.erase(fast);
					ChangePortName(foname, soname, cells);
					continue;
				}
			}
			fast++;
		}
		slow++;
	}
	
	//无用变量删除
	for (auto it = wires.begin(); it != wires.end(); it++) {
		if ((*it).porttype == POUTPUT2) {
			DetectUsed((*it).name, cells);
		}
	}
	DelNotUsed(cells);

	return true;
}

MyDesign* My_elaborate(list<perm_string>roots)
{

	MyDesign* des = new MyDesign;

	for (list<perm_string>::const_iterator root = roots.begin()
		; root != roots.end(); ++root) {

		map<perm_string, Module*>::const_iterator mod = pform_modules.find(*root);

		Module* rmod = (*mod).second;

		//rmod->scope.Mname = root->text_;
		//des->scope.set_num_ports( rmod->port_count() );

		des->scope.elaborate_sig(rmod);
		des->scope.Mname = (*root).str();
	}


	return des;
}


